#ifndef OS_FIFOIO_H
#define OS_FIFOIO_H

#include <lib/type.h>
#include <os/semaphore.h>
#include <os/mutexlock.h>

typedef struct
{
    uint8_t *buffer; // buffer
    uint8_t *head;   // head
    uint8_t *tail;   // tail
    uint32_t count;  // data count
    uint32_t size;   // buffer size
    semaphore_t full;
    semaphore_t empty;
    mutexlock_t mutex;
    uint8_t flags;
} fifo_io_t;

#define FIFO_IO_INIT(fifoname, buff, size)                      \
    {                                                           \
        .buffer = (buff),                                       \
        .size = (size),                                         \
        .head = (buff),                                         \
        .tail = (buff),                                         \
        .count = 0,                                             \
        .full = SEMAPHORE_INIT((fifoname).full, 0),             \
        .empty = SEMAPHORE_INIT((fifoname).empty, (size))       \
                     .mutex = MUTEX_LOCK_INIT((fifoname).mutex) \
    }

#define DEFINE_FIFO_IO(fifoname, buff, size) \
    fifo_io_t fifoname = FIFO_IO_INIT((fifoname), (buff), (size))

int FifoIoInit(fifo_io_t *fifo, uint8_t *buff, uint32_t size);
fifo_io_t *FifoIoAlloc(uint32_t size);
void FifoIoFree(fifo_io_t *fifo);
void FifoIoPut(fifo_io_t *fifo, uint8_t data);
uint8_t FifoIoGet(fifo_io_t *fifo);

// check if is fifo io buffer full
// return: 0:no-full     1: full
static inline bool FifoIoAvailable(fifo_io_t *fifo)
{
    return (fifo->size - fifo->count) == 0;
}

// get fifoio buffer length
static inline uint64_t FifoIoLen(fifo_io_t *fifo)
{
    return fifo->count;
}

#endif